<template>
  <el-upload
    ref="upload"
    class="fileUploadBtn"
    action="#"
    :http-request="handleRequest"
    :multiple="true"
    :limit="limit"
    :disabled="disabled"
    :on-exceed="handleExceed"
    :file-list="fileList"
    :auto-upload="false"
    :on-change="handleChange"
    :accept="accept"
  >
    <t-button slot="default" svgIcon="el-icon-plus" type="primary" size="small"> 添加</t-button>
    <div
      slot="file"
      slot-scope="{ file }"
      :class="types == 'expert' ? 'h-[116px] w-[100px]' : 'h-[88px] w-[88px]'"
      @mouseenter="handleMoveEnter(file)"
    >
      <div class="relative">
        <el-image
          v-if="file.attUrl"
          class="el-upload-list__item-thumbnail rounded-lg"
          :class="types == 'expert' ? 'h-[116px] w-[100px]' : 'h-[88px] w-[88px]'"
          :src="file.attUrl"
          alt=""
        >
        </el-image>
        <span
          v-if="!disabled"
          class="el-upload-list__item-preview absolute -right-[10px] -top-[10px] z-[1001]"
          @click="handleRemove(file)"
        >
          <i class="el-icon-remove h-[20px] w-[20px] text-[20px] text-[#1890FF]"></i>
        </span>
        <div
          v-if="file.show"
          :class="types == 'expert' ? 'h-[116px] w-[100px]' : 'h-[88px] w-[88px]'"
          class="absolute bottom-0 left-0 right-0 top-0 z-[1000] rounded-lg bg-black/50"
          @mouseout="handleMoveOut(file)"
        >
          <span class="el-upload-list__item-actions flex h-full w-full items-center justify-around p-[20px]">
            <i
              class="el-icon-zoom-in mr-[10px] h-[20px] w-[20px] text-[20px] text-white"
              @click="handlePreview(file)"
            ></i>
            <i class="el-icon-download h-[20px] w-[20px] text-[20px] text-white" @click="handleDownload(file)"></i>
          </span>
        </div>
      </div>
    </div>
    <div slot="tip">
      <slot name="tip">
        <div class="el-upload__tip text-[12px] text-[#7E8A9D]">
          {{ placeholder }}
        </div>
      </slot>
    </div>
    <el-dialog width="540px" :visible.sync="dialogVisible" class="z-[3000]" :append-to-body="true">
      <el-image class="h-[580px] w-[500px]" fit="fill" :src="dialogImageUrl" alt="" />
    </el-dialog>
  </el-upload>
</template>

<script>
import { clone } from "xe-utils";
import preview from "@/mixin/preview";
import fileIcon from "@/mixin/fileIcon";
import exportBlob from "@/util/exportBlob";
import { systemUploadFile, systemDeleteFile } from "@/api/file";

export default {
  name: "FileUploadBtnSingle",
  mixins: [preview, fileIcon],
  model: {
    prop: "value",
    event: "change",
  },
  props: {
    value: {
      type: Array,
      default: () => {
        return [];
      },
    },
    limit: {
      type: [Number, String],
      require: false,
      default: "",
    },
    // 文件大小多少兆 MB
    size: {
      type: Number,
      default: 100,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    /**
     * 接受文件类型，默认所有类型
     * 例如 ['jpg', 'png']
     */
    accept: {
      type: String,
      required: false,
      default: "",
    },
    showButtons: {
      type: Array,
      default: () => {
        return ["download", "preview", "delete"];
      },
    },
    placeholder: {
      type: String,
      require: false,
      default: "",
    },
    types: {
      type: String,
      require: false,
      default: "",
    },
  },
  data() {
    return {
      // 文件列表
      fileList: [],
      dialogVisible: false,
      dialogImageUrl: "",
    };
  },
  watch: {
    value() {
      if (Array.isArray(this.value) && this.value.length > 0) {
        this.fileList = this.value.reduce((prev, cur) => {
          prev.push({ ...cur, show: false });
          return prev;
        }, []);
      } else {
        this.fileList = [];
      }
    },
  },
  mounted() {
    if (Array.isArray(this.value) && this.value.length > 0) {
      this.fileList = this.value.reduce((prev, cur) => {
        prev.push({ ...cur, show: false });
        return prev;
      }, []);
    }
  },
  methods: {
    handleMoveEnter(file) {
      if (!file.show) {
        file.show = true;
      }
    },
    handleMoveOut(file) {
      if (file.show) {
        file.show = false;
      }
    },
    handlePreview(file) {
      this.dialogImageUrl = file.attUrl;
      this.dialogVisible = true;
    },
    handleChange(file) {
      if (file.status !== "ready") return;
      this.fileList = this.fileList.filter((item) => item.uid != file.uid) || [];
      if (this.accept) {
        const accept = this.accept.split(",");
        if (Array.isArray(accept) && accept.length > 0) {
          const type = file.name.split(".")[1];
          if (!accept.includes(`.${type}`)) {
            this.$message.error(`请输入符合要求的文件或图片，无法继续上传`);
            return false;
          }
        }
      }
      if (file.size <= 0) {
        this.$message.error(`文件「${file.originalName || file.name}」内容为空，无法继续上传`);
        return false;
      }
      if (file.size / 1024 / 1024 > this.size) {
        this.$message.error(`文件「${file.originalName || file.name}」大小超过${this.size}MB，无法继续上传`);
        return false;
      }
      this.$refs.upload.submit();
    },
    async handleRemove(file) {
      try {
        await this.$confirm("确定删除此文件?", "操作确认", {
          confirmButtonText: "确 定",
          cancelButtonText: "取 消",
          type: "warning",
        });
        if (file.id) {
          systemDeleteFile({ id: file.id }).then((data) => {
            this.$message.success("删除成功");
            this.fileList = this.fileList.filter((row) => {
              return row.id !== file.id;
            });
            this.onChange();
          });
        } else {
          // 取消请求
          file.cancel(`「${file.name}」已取消上传`);
          const _index = this.fileList.findIndex((row) => {
            return row.uid === file.uid;
          });
          this.fileList.splice(_index, 1);
        }
      } catch {
        this.$message.warning("已取消删除");
      }
    },
    // 文件超出个数限制时
    handleExceed(files, fileList) {
      this.$message.warning(
        `当前限制选择 ${this.limit} 个文件，本次选择了 ${files.length} 个文件，共选择了 ${
          files.length + fileList.length
        } 个文件`,
      );
    },
    handleSuccess(response, file) {
      // this.fileList = this.fileList.reduce((prev, cur) => {
      //   if (cur.uid === file.uid) {
      //     cur = response;
      //   }
      //   prev.push(cur);
      //   return prev;
      // }, []);
      this.onChange();
    },
    // 返回 false 或者返回 Promise 且被 reject，则停止上传
    beforeUpload(file) {
      if (this.accept) {
        const accept = this.accept.split(",");
        if (Array.isArray(accept) && accept.length > 0) {
          const type = file.name.split(".")[1];
          if (!accept.includes(`.${type}`)) {
            this.$message.error(`请输入符合要求的文件或图片，无法继续上传`);
            return false;
          }
        }
      }
      if (file.size <= 0) {
        this.$message.error(`文件「${file.originalName || file.name}」内容为空，无法继续上传`);
        return false;
      }
      if (file.size / 1024 / 1024 > this.size) {
        this.$message.error(`文件「${file.originalName || file.name}」大小超过${this.size}MB，无法继续上传`);
        return false;
      }
      this.$refs.upload.submit();
      return true;
    },
    onChange() {
      const list = clone(this.fileList, true);
      this.$emit("change", list);
    },
    handleDownload(file) {
      exportBlob({ params: { id: file.id } });
    },
    // 自定义上传实现，多文件上传有延迟
    async handleRequest(param) {
      const { file } = { ...param };
      try {
        const formData = new FormData();
        formData.append("file", param.file);
        try {
          // 上传文件
          const data = await systemUploadFile(formData);
          if (Array.isArray(data) && data.length > 0) {
            this.fileList.push({ ...data[0], show: false });
            this.onChange();
          }
        } catch {
          console.log("err");
        }
      } catch {
        this.$message.warning("上传失败");
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.fileUploadBtn {
  :deep(.el-upload--picture-card) {
    margin-top: 12px;
  }

  :deep(.el-upload-list__item) {
    display: inline-block;
    width: 160px;
    height: 90px;
    padding: 0;
    margin-right: 24px;
    background: white;
  }
}
</style>
